## Принцип подстановки Барбары Лисков

Принцип подстановки Лисков гласит: «Объекты в программе должны быть заменяемы экземплярами их подтипов без ущерба корректности работы программы».

Он предполагает отношение подтипов, называемое `сильным поведенческим подтипом`.

Этот принцип говорит нам о том, что если класс `Sub` является подтипом класса `Sup`, тогда в программе объекты типа `Sup` должны легко заменяться объектами типа `Sub` без необходимости изменения кода.

Дядя Боб включил этот принцип в число 5 лучших принципов проектирования `SOLID`.

Допустим, у нас есть базовый класс `Car`, который отвечает за тип автомобиля.

Класс `Car` наследуется подклассом `PetrolCar`.

Аналогично, базовый класс `Car` может быть унаследован другими классами, которые могут расширять его возможности.

```python
class Car:
  def __init__(self, type):
      self.type = type
  
  def __str__(self):
      return self.__class__.__name__


class PetrolCar(Car):
  ...


car = Car("Джип")
car.properties = {"Цвет": "Красный", "Коробка": "Автомат", "Объем": 6}

petrol_car = PetrolCar("Седан")
petrol_car.properties = ("Синий", "Механика", 4)
```

Стандартной спецификации для добавления свойств `Car` не существует, и разработчикам остается реализовать ее удобным для них способом.

Один разработчик может реализовать ее как `словарь`, а другой как `кортеж`.
Таким образом, она может быть реализована несколькими способами.

Пока проблем нет. Но давайте предположим, что есть задача найти все автомобили красного цвета. Давайте попробуем написать функционал

```python
cars = [car, petrol_car]
print (cars) # почему не работает


red_cars = 0
for car in cars:
    print(car.properties)
    if car.properties["Цвет"] == "Красный":
        red_cars += 1
print(f'Кол-во красных машин = ", red_cars')


```

Как видно из кода, мы пытаемся просмотреть список объектов Car.

Именно здесь мы нарушаем принцип подстановки Лисков, поскольку мы не можем заменить объекты супертипа `Car` объектами подтипа PetrolCar внутри функции поиска красных автомобилей.

Лучшим варианты было бы реализовать методы `setter и getter` в суперклассе `Car`.

С их помощью мы можем устанавливать и получать свойства автомобиля, не оставляя эту реализацию последующим разработчикам.

Таким образом, мы просто получаем свойства с помощью метода `setter`, и его реализация остается инкапсулированной в суперклассе.

Так мы сможем соблюсти принцип подстановки Лисков следующим образом:

```python

class Car:
    def __init__(self, type):
        self.type = type
        self.car_properties = {}

    def set_properties(self, color, gear, capacity):
        self.car_properties = {"Цвет": color, "Коробка": gear, "Объем": capacity}

    def get_properties(self):
        return self.car_properties


class PetrolCar(Car):
   ...

car = Car("Джип")
car.set_properties("Красный", "Автомат",  6)


petrol_car = PetrolCar("Седан")
petrol_car.set_properties("Синий", "Механика", 4)

cars = [car, petrol_car]


red_cars = 0
for car in cars:
    if car.get_properties()["Цвет"] == "Красный":
        red_cars += 1
print(f'Кол-во красных машин = ', red_cars)


```
